package com.cinnamon.rss.controller;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.cinnamon.rss.logic.RSSFeedParser;
import com.cinnamon.rss.model.Feed;
import com.cinnamon.rss.model.Item;
import com.cinnamon.rss.model.User;
import com.cinnamon.rss.repository.FeedRepository;
import com.cinnamon.rss.repository.ItemRepository;
import com.cinnamon.rss.repository.UserRepository;
import com.cinnamon.rss.service.DateConverterService;

/**
 * Handles browsers' requests.
 */
@Controller
public class WebController {

	@Autowired
	private UserRepository userRepository;
	
	@Autowired
	private FeedRepository feedRepository;

	@Autowired
	private ItemRepository itemRepository;
	
	@Autowired
	private DateConverterService converterService;

	/**
	 * Authentify the user and returns his credentials.
	 */
	@RequestMapping(value = "/authentification", method = RequestMethod.GET, 
			produces = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public List<String> authentify() {				
		String username = SecurityContextHolder.getContext().getAuthentication().getName();		
		User user = userRepository.findByUsername(username);
		String password = user.getPassword();
		List<String> userData = new ArrayList<String>();
		userData.add(username);
		userData.add(password);
		return userData;		
	}
		
	
	/**
	 * Parses an rss line and saves the Feed object.
	 */
	@RequestMapping(value = "/addFeed", method = RequestMethod.GET, 
			produces = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public List<String> addFeed(@RequestParam("rss") String rss) {	
		String username = SecurityContextHolder.getContext().getAuthentication().getName();		
		User user = userRepository.findByUsername(username);
		Feed feed = new RSSFeedParser(rss).readFeed();
		feed.setUser(user);
		List<Feed> feeds = feedRepository.findByUser(user);
		List<String> feedDetails = new ArrayList<String>();	
		if (!feeds.contains(feed)) {
			Feed feedFrom = feedRepository.save(feed);
			Long feedId = feedFrom.getId();
			String feedTitle = feedFrom.getTitle();					
			feedDetails.add(feedId.toString());
			feedDetails.add(feedTitle);			
		}
		return feedDetails;
	}

	/**
	 * Returns the user's feeds.
	 */
	@RequestMapping(value = "/feeds", method = RequestMethod.GET, 
			produces = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public List<Map<String, String>> getFeedsByUser(@RequestParam("username") String username) {			
		User user = userRepository.findByUsername(username);
		List<Feed> feeds = feedRepository.findByUser(user);
		Map<String, String> mapId = new HashMap<String, String>();
		Map<String, String> mapTitle = new HashMap<String, String>();
		List<Map<String, String>> feedData = new ArrayList<Map<String, String>>();
		for (Feed feed: feeds) {
			mapId.put("feedId", String.valueOf(feed.getId()));
			mapTitle.put("feedTitle", feed.getTitle());
		}
		feedData.add(mapId);
		feedData.add(mapTitle);
		return feedData;
	}

	
	/**
	 * Gets all items of a concrete feed  objects and renders them on a browser.
	 */
	@RequestMapping(value = "/items", method = RequestMethod.GET, produces = {
			MediaType.APPLICATION_JSON_VALUE})
	@ResponseBody	
	
	public Collection<Item> getFeedItems(@RequestParam("feedId") long feedId) {	
		Feed feed = feedRepository.findOne(feedId);
		List<Item> items = feed.getItems();
		return items;
	}

	/**
	 * Gets all items of a concrete feed  objects and renders them on a browser.
	 */
	@RequestMapping(value = "/convertedItems", method = RequestMethod.GET, produces = {
			MediaType.APPLICATION_JSON_VALUE})
	@ResponseBody	
	
	public List<Item> getFeedConvertedItems(@RequestParam("feedId") long feedId) {			
		Feed feed = feedRepository.findOne(feedId);		
		List<Item> items = feed.getItems();		
		List<Item> convertedItems = converterService.converteItems(items);		
		return convertedItems;
	}
	
	@RequestMapping(value = "/restoreFeeds", method = RequestMethod.GET, 
			produces = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public List<Map<String, String>> restoreUsertFeeds(@RequestParam("username") String username) {			
		User user = userRepository.findByUsername(username);
		List<Feed> feeds = feedRepository.findByUser(user);
		Map<String, String> feedMap = new LinkedHashMap<String, String>();
		List<Map<String, String>> feedData = new ArrayList<Map<String, String>>();
		for (Feed feed: feeds) {
			feedMap.put(String.valueOf(feed.getId()), feed.getTitle());
		}
		feedData.add(feedMap);
		return feedData;
	}
	
	/**
	 * Deletes a feed by id 
	 */
	@RequestMapping(value = "/deleteFeed", method = RequestMethod.GET, 
			produces = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public List<Object> deleteFeed(@RequestParam("feedId") long feedId) {	
		feedRepository.delete(feedId);
		return new ArrayList<Object>();
	}
	
	/**
	 * Marks/unmarks an item as stared/unstared
	 */
	@RequestMapping(value = "/starFlag", method = RequestMethod.GET, 
			produces = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public List<Object> markStared(@RequestParam("itemId") long itemId) {
		Item item = itemRepository.findOne(itemId);
		if (item.isStartFlag()) {
			item.setStartFlag(false);
			System.out.println("item flag: " + item.isStartFlag());
		} else {
			item.setStartFlag(true);
		}
		itemRepository.save(item);
		return new ArrayList<Object>();
	}

	/**
	 * Gets starred items
	 */
	@RequestMapping(value = "/staredItems", method = RequestMethod.GET, 
			produces = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public List<Item> staredItems(@RequestParam("username") String username) {
		List<Item> items = new ArrayList<Item>();
		User user = userRepository.findByUsername(username);
		List<Feed> feeds = feedRepository.findByUser(user);
		for (Feed feed: feeds) {
			for (Item item: feed.getItems()) {
				if (item.isStartFlag()) {
					items.add(item);
				}
			}
		}
		Collections.sort(items, new Comparator<Item>() {

			@Override
			public int compare(Item o1, Item o2) {
				if (o1.getPubDate() < o2.getPubDate()) {
					return 1;
				}
				if (o1.getPubDate() > o2.getPubDate()) {
					return -1;
				}
				return 0;
			}
		});			
		List<Item> stars = converterService.converteItems(items); 
		return stars;
	}
	
	/**
	 * Gets users' items
	 */
	@RequestMapping(value = "/userItems", method = RequestMethod.GET, 
			produces = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public List<Item> userItems(@RequestParam("username") String username) {		
		List<Item> items = new ArrayList<Item>();
		User user = userRepository.findByUsername(username);
		List<Feed> feeds = feedRepository.findByUser(user);
		for (Feed feed: feeds) {
			for (Item item: feed.getItems()) {
				items.add(item);
			}
		}		
		Collections.sort(items, new Comparator<Item>() {

			@Override
			public int compare(Item o1, Item o2) {
				if (o1.getPubDate() < o2.getPubDate()) {
					return 1;
				}
				if (o1.getPubDate() > o2.getPubDate()) {
					return -1;
				}
				return 0;
			}
		});			
		List<Item> convertItems = converterService.converteItems(items);		
		return convertItems;
	}

}
